package cn.juque.workflow.service.task;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.juque.common.base.BaseOperator;
import cn.juque.common.fastjson.abstracts.AbstractTypeReference;
import cn.juque.common.thread.BaseOperatorThreadLocal;
import cn.juque.common.utils.FastJsonUtil;
import cn.juque.systemservice.api.dto.employee.EmployeeInfoDetailDTO;
import cn.juque.workflow.annotation.ProcessInfo;
import cn.juque.workflow.api.enums.ProcessInstanceStatusEnum;
import cn.juque.workflow.bo.businesstask.BusinessTaskDetailBO;
import cn.juque.workflow.bo.businesstask.BusinessTaskSaveBO;
import cn.juque.workflow.bo.businesstask.BusinessTaskUpdateBO;
import cn.juque.workflow.bo.businesstask.CandidateUserBO;
import cn.juque.workflow.converter.EmployeeInfoConverter;
import cn.juque.workflow.entity.LeaveInfo;
import cn.juque.workflow.helper.EmployeeInfoHelper;
import cn.juque.workflow.helper.ProcessInfoHelper;
import cn.juque.workflow.helper.TaskInfoHelper;
import cn.juque.workflow.mapper.LeaveInfoMapper;
import com.alibaba.fastjson2.JSONObject;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.task.Task;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author juque
 * @version 1.0.0
 * <ul>
 *     <li>LeaveBusinessTaskServiceImpl</li>
 * </ul>
 * @date 2023-02-03 08:51:18
 **/
@ProcessInfo(processDefinitionKey = "Process_1gtfhxl")
@Service("leaveBusinessTaskService")
public class LeaveBusinessTaskServiceImpl implements IBusinessTaskService<LeaveInfo> {

    /**
     * 文件管理员id
     */
    private static final String FILE_ROLE_ID = "51ec9086ff9525c5ec9f8a136d444343";

    /**
     * 证券管理员ID
     */
    private static final String SC_ROLE_ID = "8c6865ab0ff40c9ca5aa236092d8f229";

    @Resource
    private LeaveInfoMapper leaveInfoMapper;

    @Resource
    private BaseOperatorThreadLocal baseOperatorThreadLocal;

    @Resource
    private EmployeeInfoHelper employeeInfoHelper;

    @Resource
    private ProcessInfoHelper processInfoHelper;

    @Resource
    private TaskInfoHelper taskInfoHelper;

    /**
     * 详情
     *
     * @param id 业务主键
     * @return BusinessTaskDetailBO
     */
    @Override
    public BusinessTaskDetailBO<LeaveInfo> detail(String id) {
        BusinessTaskDetailBO<LeaveInfo> businessTaskDetailBO = new BusinessTaskDetailBO<>();
        // 请假详情
        if (CharSequenceUtil.isNotEmpty(id)) {
            LeaveInfo leaveInfo = this.leaveInfoMapper.selectById(id);
            businessTaskDetailBO.setEntity(leaveInfo);
        }
        return businessTaskDetailBO;
    }

    /**
     * 详情
     *
     * @param taskId 任务主键
     * @return BusinessTaskDetailBO
     */
    @Override
    public BusinessTaskDetailBO<LeaveInfo> detailByTaskId(String taskId) {
        // 获取业务id
        Task task = this.taskInfoHelper.getById(taskId);
        ProcessInstance processInstance = this.processInfoHelper.getInstance(task.getProcessInstanceId());
        String businessId = processInstance.getBusinessKey();
        BusinessTaskDetailBO<LeaveInfo> businessTaskDetailBO = this.detail(businessId);
        BaseOperator baseOperator = this.baseOperatorThreadLocal.get();
        // 没有角色信息则返回null
        if (CollUtil.isEmpty(baseOperator.getRoleIdList())) {
            return businessTaskDetailBO;
        }
        Set<String> roleIdSet = CollUtil.newHashSet(baseOperator.getRoleIdList());
        // 当前处理人是证券管理员，返回空
        if (roleIdSet.contains(SC_ROLE_ID)) {
            return businessTaskDetailBO;
        }
        List<String> roleIdList = CollUtil.newArrayList();
        // 当前处理人是文件管理员，返回证券管理员
        if (roleIdSet.contains(FILE_ROLE_ID)) {
            roleIdList.add(SC_ROLE_ID);
        } else {
            // 当前处理人是其他人，返回文件管理员
            roleIdList.add(FILE_ROLE_ID);
        }
        List<EmployeeInfoDetailDTO> detailList = this.employeeInfoHelper.listEmployeeByRoleId(roleIdList);
        List<CandidateUserBO> userList = detailList.stream()
                .map(EmployeeInfoConverter::toCandidateUserBO).collect(Collectors.toList());
        businessTaskDetailBO.setCandidateUserList(userList);
        return businessTaskDetailBO;
    }

    /**
     * 保存
     *
     * @param saveBO 参数
     * @return 业务主键
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String createInstanceBefore(BusinessTaskSaveBO saveBO) {
        LeaveInfo entity = this.toEntity(saveBO.getEntity());
        this.leaveInfoMapper.insert(entity);
        return entity.getId();
    }

    /**
     * 创建实例后的操作
     *
     * @param processInstanceId 流程实例ID
     * @param businessId        业务ID
     * @return 业务ID
     */
    @Override
    public String startInstanceAfter(String processInstanceId, String businessId) {
        LeaveInfo leaveInfo = new LeaveInfo();
        leaveInfo.setId(businessId);
        leaveInfo.setProcessInstanceId(processInstanceId);
        this.leaveInfoMapper.updateById(leaveInfo);
        return businessId;
    }

    /**
     * 更新
     *
     * @param updateBO 参数
     */
    @Override
    public String update(BusinessTaskUpdateBO updateBO) {
        LeaveInfo entity = this.toEntity(updateBO.getEntity());
        this.leaveInfoMapper.updateById(entity);
        return entity.getId();
    }

    /**
     * 删除，同时删除流程实例
     *
     * @param id 业务主键
     */
    @Override
    public void delete(String id) {
        this.leaveInfoMapper.deleteById(id);
    }

    /**
     * json对象转entity
     *
     * @param jsonObject JSONObject
     * @return T
     */
    @Override
    public LeaveInfo toEntity(JSONObject jsonObject) {
        String json = jsonObject.toJSONString();
        return FastJsonUtil.parseObject(json, new AbstractTypeReference<LeaveInfo>() {
        });
    }

    /**
     * 任务完成后的操作
     *
     * @param taskId 任务ID
     */
    @Override
    public void taskFinishAfter(String taskId) {
        String instanceId = this.taskInfoHelper.getInstanceId(taskId);
        String businessId = this.processInfoHelper.getBusinessId(instanceId);
        LeaveInfo leaveInfo = this.leaveInfoMapper.selectById(businessId);
        ProcessInstanceStatusEnum statusEnum = this.processInfoHelper.getInstanceStatus(instanceId);
        if (!statusEnum.getCode().equals(leaveInfo.getApproveStatus())) {
            leaveInfo.setApproveStatus(statusEnum.getCode());
            this.leaveInfoMapper.updateById(leaveInfo);
        }
    }
}
